#include "Astronomy/SolarTerms.hpp"
#include "Astronomy/CDynamicalTime.hpp"
#include "Astronomy/Celestial/Sun.hpp"
#include "Astronomy/Constant.hpp"
#include "Astronomy/SunMoonEphemeris.hpp"

#include "Calendar/Festival.hpp"
#include "Calendar/LunarConstants.hpp"
#include "SexagenaryCycle.hpp"
#include <array>
#include <cmath>
#include <cstddef>
#include <cstdio>
#include <format>

//  619-01-21开始16598个朔日修正表 d0=1947168
// 定朔修正表解压;
#define SB_Length 16598
constexpr std::array<unsigned long, 1038> suoBalance = {
    0,          2147614720, 33554432,   256,        0,          537919488,  536870912,  32768,      536870912,  524288,     0,          16777216,   262144,
    4097,       4096,       2,          1073741826, 268435456,  4194304,    536937472,  541395072,  2281718818, 524560,     268574788,  1141409793, 285352448,
    71305344,   2147762722, 41947400,   270664772,  1149796369, 270671876,  1140885505, 4456992,    671158408,  35669058,   16657,      2101312,    32768,
    0,          0,          0,          262144,     0,          0,          0,          0,          0,          0,          512,        264,        0,
    16777216,   0,          67108864,   0,          0,          0,          0,          0,          1073741824, 1,          0,          0,          0,
    1073741824, 0,          0,          0,          1052672,    272896004,  1073741841, 269484288,  262144,     266240,     16846912,   0,          1281,
    2097152,    1073743936, 268501008,  269484036,  1074791440, 1090523136, 64,         32784,      0,          1048576,    16640,      0,          0,
    4194304,    69632,      0,          272896000,  1052740,    68157505,   67113025,   1052673,    16,         71303172,   16842752,   16778257,   66560,
    1073807376, 268435972,  67108864,   17825808,   268452112,  1065220,    268452100,  272629828,  1140850753, 286261264,  262144,     16781313,   64,
    65,         67109888,   16777476,   1078198336, 16,         66560,      1073759248, 1130752,    64,         1074003969, 65792,      0,          1,
    262148,     1024,       1024,       65540,      17409,      4456720,    268439616,  1,          16384,      64,         0,          4194304,    64,
    1,          262144,     1073742864, 279552,     4,          1091568641, 1077936400, 272629764,  268517632,  272646404,  67113025,   17825792,   4456452,
    67112960,   266305,     67109953,   1141968912, 286262288,  71565316,   1090584577, 4260864,    1073759248, 16843024,   16793856,   71565377,   286326784,
    16388,      67125504,   269488388,  4460544,    1077936128, 285278224,  67126336,   1090785280, 16846912,   71368705,   1114368,    256,        1073759297,
    268439808,  1114180,    1141900304, 17829904,   16781312,   1074005008, 268439808,  1049600,    1090797584, 285278212,  4260096,    272630020,  69892,
    1073741825, 272891904,  1052676,    68157505,   67113024,   1141903361, 17826832,   4456452,    17891329,   16778240,   1073808400, 1090584848, 285230084,
    71565316,   17891329,   268451840,  1064960,    4356,       4210752,    1077940288, 286326800,  71319556,   16777473,   16781376,   67372033,   1115136,
    269484036,  67125312,   4368,       268501060,  1077953552, 17842176,   16448,      1074004032, 268439824,  67109952,   1074020369, 285474820,  4457472,
    268436480,  4356,       1073742912, 262400,     272699396,  71319553,   16448,      67108929,   1091568704, 272891904,  68227072,   537134081,  10486784,
    1073742865, 285230084,  4456708,    1091633153, 4211712,    4194304,    1073758464, 16448,      67112961,   1091633152, 4472836,    67109120,   266240,
    263232,     69648,      269484048,  71581700,   1090588945, 4259904,    1077953536, 16843008,   16640,      67108865,   16781584,   1092,       1140867089,
    286265344,  266240,     16,         268435472,  67109956,   1090781456, 268505092,  4259840,    268501252,  67109121,   1141900353, 268697616,  1118208,
    68157441,   1052672,    1140854801, 1090535440, 272892160,  1114112,    1090798592, 65536,      1073807632, 285213956,  71307525,   1091633153, 272908288,
    1048832,    1052672,    268439620,  1078005776, 16778256,   4472832,    1074794753, 16777280,   66624,      67174657,   1065988,    67108868,   1090588673,
    272630852,  1209024528, 1074794512, 17039360,   1074008128, 4112,       71304260,   1090519313, 285212932,  272892932,  272696320,  65540,      67109892,
    272,        272699460,  67125313,   1064961,    1140850689, 1091584064, 268697872,  67174400,   1090798608, 1090781200, 1073742864, 285213700,  71569668,
    68222976,   278528,     272634112,  16388,      268451908,  1078001729, 1090585664, 272908288,  68227328,   262208,     263233,     67109889,   269501444,
    67125252,   1074860033, 272892992,  1077936144, 1073758480, 17055808,   266240,     1090523137, 4195396,    1141899537, 285479172,  272892932,  4259840,
    268502032,  67109892,   1090519057, 272633860,  71320641,   68157441,   68174145,   17842177,   17039633,   4194308,    1140868096, 1090785296, 1090786304,
    285474816,  272896016,  67174468,   17055744,   272699648,  272629764,  272629764,  71368961,   17892417,   268713984,  67178752,   64,         67113025,
    68161553,   269500432,  272646416,  68227072,   17040448,   1078001680, 1090584848, 17039616,   266497,     1090523201, 268698688,  68157713,   269484292,
    272633924,  4263952,    268502032,  272630784,  1074790417, 268435460,  71369793,   68223233,   68174080,   68173829,   1090519297, 4194308,    1141916673,
    1091571728, 1090785280, 1090785360, 4460560,    4259908,    16384,      268439808,  272695300,  272696580,  71368706,   68224004,   17055761,   4264192,
    68173888,   67112961,   1141899265, 1091584064, 4473104,    67178752,   16794688,   1073741840, 1090519056, 17040388,   67375364,   68161604,   285492288,
    4260112,    269500420,  272646212,  1078001728, 1090585664, 272630784,  1141964816, 285474820,  67372097,   68224001,   1065988,    67125252,   1141899520,
    268697668,  1140851713, 1091584272, 17055808,   1090785344, 1090785281, 272629828,  1074790401, 285479168,  272892932,  272696320,  272696340,  68224004,
    17425,      4198656,    67109952,   68173825,   68174145,   17842176,   1090797841, 4264192,    1066048,    1074008080, 1090520080, 285474820,  268701712,
    68161604,   16794688,   4264208,    268435460,  272646148,  4260097,    16843841,   1090782209, 1140920336, 286277636,  67375169,   68161553,   269501456,
    272646416,  1141899520, 285474820,  71368705,   1091600656, 17056000,   266497,     17043457,   285474880,  67174401,   285212928,  272896068,  272699408,
    1346438160, 272696320,  1074807825, 268697856,  541131840,  0,          258,        33554432,   0,          4194304,    8,          0,          0,
    0,          16,         0,          0,          8388608,    0,          0,          5,          0,          0,          134217728,  0,          128,
    32,         0,          0,          2147483648, 0,          0,          0,          0,          32770,      0,          8,          0,          512,
    0,          32,         0,          0,          0,          0,          2048,       1073741824, 0,          0,          0,          32,         0,
    0,          134217728,  0,          0,          0,          0,          0,          0,          8,          0,          8196,       0,          0,
    2097152,    0,          0,          64,         2048,       2147483648, 0,          0,          2097184,    0,          32768,      512,        8,
    0,          0,          0,          2147483648, 524288,     128,        0,          0,          268435456,  0,          8,          0,          32,
    0,          64,         0,          134217728,  0,          0,          512,        0,          0,          0,          0,          0,          0,
    128,        0,          0,          536870912,  2,          0,          16777216,   32,         33554432,   8192,       0,          0,          512,
    0,          0,          0,          0,          16384,      0,          0,          16777216,   0,          32768,      8192,       32,         545259520,
    0,          0,          256,        0,          0,          512,        2,          0,          0,          0,          0,          0,          32,
    8192,       268435456,  17408,      1073741824, 131072,     536870912,  0,          2048,       0,          2147483648, 0,          0,          8192,
    0,          0,          0,          0,          0,          2048,       8,          0,          0,          0,          8388608,    0,          0,
    0,          524288,     0,          1024,       0,          0,          32,         0,          0,          0,          0,          64,         0,
    0,          33554432,   8388608,    0,          0,          1073742080, 0,          0,          134217736,  0,          0,          0,          131072,
    512,        0,          0,          0,          0,          0,          524288,     0,          0,          0,          0,          0,          0,
    2048,       262144,     2,          0,          16777216,   0,          0,          0,          0,          0,          268435456,  0,          0,
    0,          0,          0,          0,          1,          0,          0,          1073741825, 8192,       32,         0,          2097152,    0,
    0,          0,          0,          134217984,  33554432,   0,          0,          0,          67109504,   128,        536870912,  0,          0,
    0,          0,          0,          537165824,  8192,       0,          1,          0,          2097152,    0,          0,          0,          0,
    4194304,    256,        0,          0,          0,          0,          67633152,   0,          0,          1073741825, 0,          0,          1082130432,
    0,          4194304,    0,          0,          0,          8,          0,          0,          0,          0,          0,          1048576,    0,
    0,          0,          0,          0,          0,          0,          0,          0,          0,          0,          0,          0,          0,
    2048,       0,          0,          0,          0,          0,          0,          0,          0,          0,          0,          1,          0,
    0,          0,          0,          0,          0,          0,          0,          0,          2097152,    0,          8192,       4096,       0,
    0,          2,          0,          16777216,   0,          0,          0,          0,          0,          0,          0,          0,          0,
    32768,      0,          33554432,   0,          0,          0,          557056,     0,          0,          0,          0,          0,          0,
    0,          0,          0,          0,          0,          0,          0,          268435456,  4194304,    0,          0,          0,          0,
    0,          0,          0,          0,          0,          0,          0,          0,          0,          2,          8192,       0,          0,
    134217728,  0,          0,          0,          0,          0,          0,          33554432,   524288,     0,          33554432,   32,         8,
    536870912,  8388608,    0,          0,          262144,     0,          524288,     134217728,  0,          0,          4194304,    0,          8388608,
    32,         33554432,   0,          0,          536870912,  0,          32768,      0,          0,          0,          0,          0,          0,
    0,          134217728,  0,          0,          0,          0,          2097152,    0,          0,          4096,       524288,     8192,       2048,
    0,          8,          0,          0,          0,          0,          262144,     0,          0,          8192,       4096,       0,          0,
    33554434,   0,          131072,     0,          0,          0,          0,          268435456,  2097152,    0,          0,          0,          0,
    0,          0,          0,          0,          65536,      2097152,    0,          32,         0,          0,          0,          0,          0,
    0,          0,          0,          0,          0,          1024,       4,          0,          0,          0,          0,          0,          128,
    0,          0,          0,          0,          0,          0,          0,          4,          0,          8388608,    4194304,    0,          0,
    0,          16777216,   0,          0,          0,          2048,       0,          0,          0,          0,          8388608,    32768,      0,
    0,          0,          0,          0,          0,          0,          0,          0,          0,          128,        32,         0,          0,
    0,          0,          0,          0,          0,          2,          0,          4096,       0,          0,          0};

#define QB_Length 7567
// 1645-09-23开始7567个节气修正表
// 定气修正表解压;
// suoS 解压后，然后 每32位 ;
constexpr std::array<unsigned long, 473> qiBalance = {
    134217728, 1024,      672,        0,          0,          0,          134217728,  17408,     33312,      0,          32768,      8192,       33554432,
    134234112, 33280,     65536,      266240,     16785408,   131072,     16392,      2129928,   0,          4460608,    8192,       131073,     16392,
    32776,     8388608,   2151944192, 139264,     131073,     0,          8,          10485760,  2148532224, 131072,     1,          0,          2056,
    44048384,  1048576,   131072,     257,        0,          67110912,   44040192,   1048576,   0,          256,        2,          67241984,   2191523840,
    0,         0,         536870912,  0,          1073743872, 2183135232, 0,          268435456, 536870912,  256,        1074266112, 2181038080, 32,
    268435456, 536870916, 0,          1074266114, 2148007936, 0,          268435460,  536870980, 65538,      2,          524288,     0,          128,
    536903748, 65538,     2,          134742016,  0,          128,        32832,      65538,     0,          134742016,  0,          672,        16,
    0,         0,         134217728,  536871936,  672,        0,          16777216,   0,         134218752,  16384,      33440,      0,          4096,
    16785408,  134217728, 16392,      2130464,    0,          4160,       8192,       0,         16392,      33280,      0,          266240,     139264,
    0,         8,         32776,      0,          262144,     139264,     131073,     0,         8,          8388608,    5505024,    131072,     131073,
    0,         2056,      0,          0,          0,          131072,     0,          0,         0,          2147483648, 0,          0,          0,
    8,         0,         0,          0,          0,          512,        0,          8388608,   0,          8388608,    0,          0,          2048,
    0,         0,         0,          4,          0,          524288,     0,          0,         0,          0,          65536,      0,          0,
    0,         0,         536870912,  0,          0,          0,          0,          0,         0,          0,          0,          0,          0,
    0,         0,         0,          0,          0,          0,          0,          0,         0,          0,          524288,     16384,      0,
    0,         16777216,  0,          0,          0,          2097280,    0,          0,         0,          134218752,  0,          0,          0,
    262144,    0,         0,          0,          32,         0,          0,          0,         0,          0,          0,          0,          0,
    0,         0,         0,          0,          0,          0,          0,          0,         0,          0,          0,          0,          0,
    0,         0,         0,          0,          0,          268435456,  0,          0,         8,          0,          0,          0,          256,
    0,         0,         8388608,    0,          0,          0,          0,          2048,      0,          0,          0,          4,          0,
    0,         2097152,   0,          0,          0,          0,          0,          0,         1024,       0,          0,          0,          0,
    0,         0,         0,          80,         0,          0,          0,          0,         0,          0,          0,          0,          0,
    16384,     0,         0,          0,          0,          0,          0,          0,         0,          0,          0,          0,          4,
    0,         0,         16777216,   0,          0,          268435456,  32768,      0,         262144,     0,          1025,       0,          0,
    0,         0,         8192,       0,          0,          0,          0,          0,         0,          0,          0,          0,          0,
    5242880,   0,         0,          256,        0,          0,          1048576,    272629760, 0,          0,          0,          0,          0,
    0,         0,         0,          0,          0,          0,          0,          0,         0,          8,          0,          1073741824, 0,
    256,       0,         0,          0,          0,          0,          4,          67174400,  0,          0,          1024,       0,          0,
    0,         0,         2097152,    0,          0,          0,          0,          0,         0,          0,          0,          80,         0,
    0,         0,         16384,      1048576,    16,         0,          0,          0,         0,          0,          0,          0,          0,
    0,         0,         0,          0,          0,          0,          0,          0,         0,          0,          17039360,   0,          1,
    0,         0,         0,          0,          0,          0,          0,          0,         0,          0,          0,          0,          0,
    32,        0,         0,          0,          0,          0,          2147483648, 0,         32,         0,          0,          0,          0,
    0,         0,         0,          0,          0,          0,          0,          0,         0,          0,          0,          0,          0,
    0,         0,         0,          0,          0,          0,          0,          0,         0,          0,          0,          0,          0,
    0,         536870912, 0,          0,          4096,       0,          0,          0,         0,          0,          0,          0,          0,
    0,         0,         0,          0,          0};

// 朔直线拟合参数;
constexpr std::array<SolarTermsCoefficient, 12> suoKB = {
    1457698.231017,
    29.53067166, // -721-12-17 h=0.00032 古历·春秋
    1546082.512234,
    29.53085106, // -479-12-11 h=0.00053 古历·战国
    1640640.735300,
    29.53060000, // -221-10-31 h=0.01010 古历·秦汉
    1642472.151543,
    29.53085439, // -216-11-04 h=0.00040 古历·秦汉

    1683430.509300,
    29.53086148, // -104-12-25 h=0.00313 汉书·律历志(太初历)平气平朔
    1752148.041079,
    29.53085097, //   85-02-13 h=0.00049 后汉书·律历志(四分历)
                 // 1807665.420323,29.53059851, //  237-02-12 h=0.00033 晋书·律历志(景初历)
    1807724.481520,
    29.53059851, //  237-04-12 h=0.00033 晋书·律历志(景初历)
    1883618.114100,
    29.53060000, //  445-01-24 h=0.00030 宋书·律历志(何承天元嘉历)
    1907360.704700,
    29.53060000, //  510-01-26 h=0.00030 宋书·律历志(祖冲之大明历)
    1936596.224900,
    29.53060000, //  590-02-10 h=0.01010 随书·律历志(开皇历)
    1939135.675300,
    29.53060000, //  597-01-24 h=0.00890 随书·律历志(大业历)
    1947168.00,
    0.0 //  619-01-21
};

// 气直线拟合参数
constexpr std::array<SolarTermsCoefficient, 36> qiKB = {
    1640650.479938, 15.21842500,  // -221-11-09 h=0.01709 古历·秦汉
    1642476.703182, 15.21874996,  // -216-11-09 h=0.01557 古历·秦汉
    1683430.515601, 15.218750011, // -104-12-25 h=0.01560 汉书·律历志(太初历)平气平朔 回归年=365.25000
    1752157.640664, 15.218749978, //   85-02-23 h=0.01559 后汉书·律历志(四分历) 回归年=365.25000
    1807675.003759, 15.218620279, //  237-02-22 h=0.00010 晋书·律历志(景初历) 回归年=365.24689
    1883627.765182, 15.218612292, //  445-02-03 h=0.00026 宋书·律历志(何承天元嘉历) 回归年=365.24670
    1907369.128100, 15.218449176, //  510-02-03 h=0.00027 宋书·律历志(祖冲之大明历) 回归年=365.24278
    1936603.140413, 15.218425000, //  590-02-17 h=0.00149 随书·律历志(开皇历) 回归年=365.24220
    1939145.524180, 15.218466998, //  597-02-03 h=0.00121 随书·律历志(大业历) 回归年=365.24321
    1947180.798300, 15.218524844, //  619-02-03 h=0.00052 新唐书·历志(戊寅元历)平气定朔 回归年=365.24460
    1964362.041824, 15.218533526, //  666-02-17 h=0.00059 新唐书·历志(麟德历) 回归年=365.24480
    1987372.340971, 15.218513908, //  729-02-16 h=0.00096 新唐书·历志(大衍历,至德历) 回归年=365.24433
    1999653.819126, 15.218530782, //  762-10-03 h=0.00093 新唐书·历志(五纪历) 回归年=365.24474
    2007445.469786, 15.218535181, //  784-02-01 h=0.00059 新唐书·历志(正元历,观象历) 回归年=365.24484
    2021324.917146, 15.218526248, //  822-02-01 h=0.00022 新唐书·历志(宣明历) 回归年=365.24463
    2047257.232342, 15.218519654, //  893-01-31 h=0.00015 新唐书·历志(崇玄历) 回归年=365.24447
    2070282.898213, 15.218425000, //  956-02-16 h=0.00149 旧五代·历志(钦天历) 回归年=365.24220
    2073204.872850, 15.218515221, //  964-02-16 h=0.00166 宋史·律历志(应天历) 回归年=365.24437
    2080144.500926, 15.218530782, //  983-02-16 h=0.00093 宋史·律历志(乾元历) 回归年=365.24474
    2086703.688963, 15.218523776, // 1001-01-31 h=0.00067 宋史·律历志(仪天历,崇天历) 回归年=365.24457
    2110033.182763, 15.218425000, // 1064-12-15 h=0.00669 宋史·律历志(明天历) 回归年=365.24220
    2111190.300888, 15.218425000, // 1068-02-15 h=0.00149 宋史·律历志(崇天历) 回归年=365.24220
    2113731.271005, 15.218515671, // 1075-01-30 h=0.00038 李锐补修(奉元历) 回归年=365.24438
    2120670.840263, 15.218425000, // 1094-01-30 h=0.00149 宋史·律历志 回归年=365.24220
    2123973.309063, 15.218425000, // 1103-02-14 h=0.00669 李锐补修(占天历) 回归年=365.24220
    2125068.997336, 15.218477932, // 1106-02-14 h=0.00056 宋史·律历志(纪元历) 回归年=365.24347
    2136026.312633, 15.218472436, // 1136-02-14 h=0.00088 宋史·律历志(统元历,乾道历,淳熙历) 回归年=365.24334
    2156099.495538, 15.218425000, // 1191-01-29 h=0.00149 宋史·律历志(会元历) 回归年=365.24220
    2159021.324663, 15.218425000, // 1199-01-29 h=0.00149 宋史·律历志(统天历) 回归年=365.24220
    2162308.575254, 15.218461742, // 1208-01-30 h=0.00146 宋史·律历志(开禧历) 回归年=365.24308
    2178485.706538, 15.218425000, // 1252-05-15 h=0.04606 淳祐历 回归年=365.24220
    2178759.662849, 15.218445786, // 1253-02-13 h=0.00231 会天历 回归年=365.24270
    2185334.020800, 15.218425000, // 1271-02-13 h=0.00520 宋史·律历志(成天历) 回归年=365.24220
    2187525.481425, 15.218425000, // 1277-02-12 h=0.00520 本天历 回归年=365.24220
    2188621.191481, 15.218437494, // 1280-02-13 h=0.00015 元史·历志(郭守敬授时历) 回归年=365.24250
    2322147.760000, 0.0           // 1645-09-21
};

double SolarTerms::CalcMonthPolicyLow(double W)
{
    double v = 7771.37714500204;
    double t = (W + 1.08472) / v;
    t -= (-0.0000331 * t * t + 0.10976 * cos(0.785 + 8328.6914 * t) + 0.02224 * cos(0.187 + 7214.0629 * t) - 0.03342 * cos(4.669 + 628.3076 * t)) / v +
         (32 * (t + 1.8) * (t + 1.8) - 20.0) / 86400 / 36525.0;
    return t * 36525.0 + 8.0 / 24.0;
}
double SolarTerms::CalcSolarTermPolicyLow(double W)
{
    double v = 628.3319653318;
    // 第一次估算,误差2天以内;
    double t = (W - 4.895062166) / v;
    // 第二次估算,误差2小时以内;
    t -= (53 * t * t + 334116 * cos(4.67 + 628.307585 * t) + 2061.0 * cos(2.678 + 628.3076 * t) * t) / v / 10000000.0;

    double L = 48950621.66 + 6283319653.318 * t + 53 * t * t // 平黄经;
               + 334166.0 * cos(4.669257 + 628.307585 * t)   // 地球椭圆轨道级数展开;
               + 3489.0 * cos(4.6261 + 1256.61517 * t)       // 地球椭圆轨道级数展开;
               + 2060.6 * cos(2.67823 + 628.307585 * t) * t  // 一次泊松项;
               - 994.0 - 834.0 * sin(2.1824 - 33.75705 * t); // 光行差与章动修正;

    t -= (L / 10000000.0 - W) / 628.332 + (32 * (t + 1.8) * (t + 1.8) - 20.0) / 86400.0 / 36525.0;
    return t * 36525 + 8.0 / 24.0;
}

double SolarTerms::CalcSolarTermPolicyHigh(double W)
{
    double t  = CelestialSun::GetEclipticLongitudeTimeLow(W) * 36525.0;
    t         = t - CDynamicalTime::TDUT(t) + 8.0 / 24.0;

    double tt = (t + 0.5);
    double v  = (tt - floor(tt)) * 86400.0;

    if (v < 1200.0 || v > (86400.0 - 1200.0))
        t = CelestialSun::GetEclipticLongitudeTime(W) * 36525.0 - CDynamicalTime::TDUT(t) + 8.0 / 24.0;
    return t;
}

double SolarTerms::CalcMonthPolicyHigh(double W)
{
    double t  = SunMoonEphemeris::GetEclipticLongitudeTimeLow(W) * 36525.0;
    t         = t - CDynamicalTime::TDUT(t) + 8.0 / 24.0;

    double tt = (t + 0.5);
    double v  = (tt - floor(tt)) * 86400.0;

    if (v < 1800.0 || v > (86400.0 - 1800.0))
        t = SunMoonEphemeris::GetEclipticLongitudeTime(W) * 36525.0 - CDynamicalTime::TDUT(t) + 8.0 / 24.0;
    return t;
}

#define J1960 (2436935.0)

double SolarTerms::LookUpTheTable(const double jd, SolarTermsCoefficient *data, const size_t size, const size_t pc) noexcept
{
    for (int i = 0; i < size; i++)
    {
        if ((jd + pc) < data[i + 1].jd)
            break;

        double D = data[i].jd + data[i].coefficient * floor((jd + pc - data[i].jd) / data[i].coefficient);
        D        = floor(D + 0.5);

        // 如果使用太初历计算-103年1月24日的朔日,结果得到的是23日,这里修正为24日(实历)。修正后仍不影响-103的无中置闰;
        // 如果使用秦汉历，得到的是24日，本行D不会被执行。;
        if (D == 1683460.0)
            D++;
        return D - Constants::J2000;
    }
    return 0.0;
}

double SolarTerms::CalcTableValue(double D, int indexSize, unsigned long *dataPtr) noexcept
{
    // 计算数组索引;
    int arrayIndex = indexSize / 16;
    // 位移;
    int shift      = indexSize % 16;
    // 根据索引获取数据;
    auto data      = dataPtr[arrayIndex];
    // 按位取数据;
    int n          = (data >> (shift * 2)) & 3;

    if (n == 1)
        return D + 1;
    if (n == 2)
        return D - 1;
    return D;
}

double SolarTerms::CalcQi(double jd) noexcept
{
    jd += Constants::J2000;

    const double pc       = 7;
    const size_t qiKBSize = qiKB.size();

    const double firstJd  = qiKB[0].jd - pc;
    const double lastJd   = qiKB[qiKBSize - 1].jd - pc;

    const double W        = (floor((jd + pc - 2451259.0) / 365.2422 * 24.0) * Constants::PI / 12.0);
    while (jd >= firstJd)
    {
        if (jd >= J1960)
            break;
        // 定气;
        if (jd >= lastJd)
        {
            double D      = floor(CalcSolarTermPolicyLow(W) + 0.5);
            // 计算索引大小;
            int indexSize = (int)floor((jd - lastJd) / 365.2422 * 24.0);
            // 返回;
            return CalcTableValue(D, indexSize, (unsigned long *)qiBalance.data());
        }
        // 平气;
        return LookUpTheTable(jd, (SolarTermsCoefficient *)qiKB.data(), qiKBSize, pc);
    }
    // 平气朔表中首个之前，使用现代天文算法。
    // 1960.1.1以后，使用现代天文算法 (这一部分调用了qi_high和so_high,所以需星历表支持);
    return floor(CalcSolarTermPolicyHigh(W) + 0.5);
}

double SolarTerms::CalcSuo(double jd) noexcept
{
    jd += Constants::J2000;

    const double pc        = 7;
    const size_t suoKBSize = suoKB.size();

    const double firstJd   = suoKB[0].jd - pc;
    const double lastJd    = suoKB[suoKBSize - 1].jd - pc;

    const double W         = (floor((jd + pc - 2451551.0) / 29.5306) * Constants::PI * 2.0);
    while (jd >= firstJd)
    {
        if (jd >= J1960)
            break;

        // 定朔;;
        if (jd >= lastJd)
        {
            double D      = floor(CalcMonthPolicyLow(W) + 0.5);
            // 计算索引大小;
            int indexSize = (int)floor((jd - lastJd) / 29.5306);
            // 返回;
            return CalcTableValue(D, indexSize, (unsigned long *)suoBalance.data());
        }
        // 平朔;
        return LookUpTheTable(jd, (SolarTermsCoefficient *)suoKB.data(), suoKBSize, pc);
    }
    // 平朔表中首个之前，使用现代天文算法。
    // 1960.1.1以后，使用现代天文算法 (这一部分调用了qi_high和so_high,所以需星历表支持);
    return floor(CalcMonthPolicyHigh(W) + 0.5);
}

std::string SolarTerms::GetLunarMonthName(int y, int lmIndex)
{
    // 返回的字符串;
    std::string result;
    // 农历月份序号;
    const int i = lmIndex;
    // -721年至-104年的后九月及月建问题,与朔有关，与气无关;
    // 确定年份;
    double YY   = floor((this->MiddleSolarTermArray[SolarTerm::LastWinterSolstice] + 10.0 + 180.0) / 365.2422) + 2000.0;
    if (YY >= -721 && YY <= -104)
    {
        double yy = 0.0;

        struct EnactmentCal
        {
            // 颁行历年首;
            double EnactmentJd;
            // 闰月名称;
            const char *LeapName;
            // 月建;
            int FirstMonth;
        };
        EnactmentCal ns[3] = {};
        for (int i = 0; i < 3; i++)
        {
            yy = YY + i - 1;
            // 颁行历年首, 闰月名称, 月建;
            if (yy >= -721)
            {
                // 春秋历,ly为-722.12.17;
                ns[i].EnactmentJd = this->CalcSuo(1457698 - Constants::J2000 + floor(0.342 + (yy + 721) * 12.368422) * 29.5306);
                ns[i].LeapName    = "十三";
                ns[i].FirstMonth  = 2;
            }
            if (yy >= -479)
            {
                // 战国历,ly为-480.12.11;
                ns[i].EnactmentJd = this->CalcSuo(1546083 - Constants::J2000 + floor(0.500 + (yy + 479) * 12.368422) * 29.5306);
                ns[i].LeapName    = "十三";
                ns[i].FirstMonth  = 2;
            }
            if (yy >= -220)
            {
                // 秦汉历,ly为-221.10.31
                ns[i].EnactmentJd = this->CalcSuo(1640641 - Constants::J2000 + floor(0.866 + (yy + 220) * 12.369000) * 29.5306);

                ns[i].LeapName    = "后九";
                ns[i].FirstMonth  = 11;
            }
        }
        int nn, f1;
        // for (int i = 0; i < 14; i++)
        //{
        for (nn = 2; nn >= 0; nn--)
            if (this->CloseSuoArray[i] >= ns[nn].EnactmentJd)
                break;
        // 该月积数;
        f1 = floor((this->CloseSuoArray[i] - ns[nn].EnactmentJd + 15) / 29.5306);
        if (f1 < 12)
            result = LunarConstants::CnMonthNames[(f1 + ns[nn].FirstMonth) % 12];
        else
            result = ns[nn].LeapName;
        //}
        return result;
    }
    //
    // 名称转换(月建别名)
    // for (int i = 0; i < 14; i++)
    //{
    // Dm初一的儒略日
    auto Dm = this->CloseSuoArray[i] + Constants::J2000;
    // 月建序号;
    int v2  = this->YearCountArray[i];
    // 月建对应的默认月名称：建子十一,建丑十二,建寅为正……
    int mc  = v2 % 12;
    //  8.01.15至 23.12.02 建子为十二,其它顺推;
    if (Dm >= 1724360 && Dm <= 1729794)
    {
        mc = (v2 + 1) % 12;
    }
    // 237.04.12至239.12.13 建子为十二,其它顺推;
    else if (Dm >= 1807724 && Dm <= 1808699)
    {
        mc = (v2 + 1) % 12;
    }
    // 761.12.02至762.03.30 建子为正月,其它顺推;
    else if (Dm >= 1999349 && Dm <= 1999467)
    {
        mc = (v2 + 2) % 12;
    }
    // 689.12.18至700.11.15 建子为正月,建寅为一月,其它不变;
    else if (Dm >= 1973067 && Dm <= 1977052)
    {
        if (v2 % 12 == 0)
        {
            result = "正";
        }
        if (v2 == 2)
        {
            result = "一";
        }
    }
    // 239.12.13及23.12.02均为十二月,为避免两个连续十二月，此处改名;
    if (Dm == 1729794 || Dm == 1808699)
    {
        result = "拾贰";
    }
    if (result.empty())
        return LunarConstants::CnMonthNames[mc];
    return result;
    //}
}

void SolarTerms::CalcYear(double jd) noexcept
{
    auto A   = this->MiddleSolarTermArray;
    auto B   = this->CloseSuoArray;
    // 该年的气;
    // 355是2000.12冬至,得到较靠近jd的冬至估计值;
    double W = floor((jd - 355 + 183) / 365.2422) * 365.2422 + 355.0;
    if (this->CalcQi(W) > jd)
        W -= 365.2422;

    // 计算一年的气;
    // 补算二气,确保一年中所有月份的“气”全部被计算在内;
    // 去年小雪 到明年立春;
    for (int i = 0; i < SolarTermsMax; i++)
    {
        // 25个节气时刻(北京时间),从冬至开始到下一个冬至以后;
        A[i] = this->CalcQi(W + (15.2184 * (i - (int)SolarTerm::LastWinterSolstice)));
    }

    // 今年"首朔"的日月黄经差w；求较靠近冬至的朔日;
    double w = this->CalcSuo(A[SolarTerm::LastWinterSolstice]);
    if (w > A[SolarTerm::LastWinterSolstice])
        w -= 29.53;
    // 该年所有朔,包含14个月的始末
    for (int i = 0; i < LunarMonthMax + 1; i++)
    {
        B[i] = this->CalcSuo(w + 29.5306 * i);
    }

    this->LeapIndex = 0;
    for (int i = 0; i < LunarMonthMax; i++)
    {
        // 月大小;
        this->DayCountOfMonthArray[i] = B[i + 1] - B[i];
        // 月序初始化;
        this->YearCountArray[i]       = i;
    }
    //
    // 无中气置闰法确定闰月,(气朔结合法,数据源需有冬至开始的的气和朔);
    if (B[13] <= A[SolarTerm::WinterSolstice])
    {
        int i = 0;
        // 第13月的月末没有超过冬至(不含冬至),说明今年含有13个月;
        // 在13个月中找第1个没有中气的月份;
        for (int i = 1; B[i + 1] > A[2 * i + (int)SolarTerm::LastWinterSolstice] && i < 13; i++)
            ;
        this->LeapIndex = i;
        for (; i < LunarMonthMax; i++)
            this->YearCountArray[i]--;
    }
    //
}

double SolarTerms::CalcQiAccurate(double W) noexcept
{
    double t = CelestialSun::GetEclipticLongitudeTime(W) * 36525.0;
    return t - CDynamicalTime::TDUT(t) + 8.0 / 24.0;
}

double SolarTerms::CalcSuoAccurate(double W) noexcept
{
    double t = SunMoonEphemeris::GetEclipticLongitudeTime(W) * 36525.0;
    return t - CDynamicalTime::TDUT(t) + 8.0 / 24.0;
}

double SolarTerms::CalcQiAccurateOnJulianDate(double jd) noexcept
{
    const double d = Constants::PI / 12.0;
    double       w = floor((jd + 293.0) / 365.2422 * 24.0) * d;

    double a       = CalcQiAccurate(w);
    if (a - jd > +5.0)
        return CalcQiAccurate(w - d);
    if (a - jd < -5.0)
        return CalcQiAccurate(w + d);
    return a;
}

double SolarTerms::CalcSuoAccurateOnJulianDate(double jd) noexcept
{
    return CalcSuoAccurate(floor((jd + 8.0) / 29.5306) * Constants::PI * 2);
}

void SolarTerms::GetDayName(double jd, Date &date, Festival &festival) noexcept
{
    SexagenaryCycle w;

    int cur_xz = this->MiddleSolarTermArray[SolarTerm::SummerSolstice] - jd;
    int cur_lq = this->MiddleSolarTermArray[SolarTerm::AutumnCommences] - jd;
    int cur_mz = this->MiddleSolarTermArray[SolarTerm::CornOnEar] - jd;
    int cur_xs = this->MiddleSolarTermArray[SolarTerm::ModerateHeat] - jd;
    int cur_dz = this->MiddleSolarTermArray[SolarTerm::LastWinterSolstice] - jd;

    // 节气的取值范围是0-23;
    auto qk    = (int)floor((jd - this->MiddleSolarTermArray[SolarTerm::LastWinterSolstice] - 7) / 15.2184);
    if (qk < 23 && jd >= this->MiddleSolarTermArray[qk + 1 + SolarTerm::LastWinterSolstice])
        qk++;
    if (jd == this->MiddleSolarTermArray[qk])
        printf("%s", LunarConstants::CnSolarTermsNames[qk]);
    // ob.Ljq = obb.jqmc[qk];
    // else
    // ob.Ljq ='';

    if (cur_xz >= 20 && cur_xz < 30 && w.heanvenlyStem == HeavenlyStem::Geng)
        festival.B += "初伏 ";
    if (cur_xz >= 30 && cur_xz < 40 && w.heanvenlyStem == HeavenlyStem::Geng)
        festival.B += "中伏 ";
    if (cur_lq >= 0 && cur_lq < 10 && w.heanvenlyStem == HeavenlyStem::Geng)
        festival.B += "末伏 ";
    if (cur_mz >= 0 && cur_mz < 10 && w.heanvenlyStem == HeavenlyStem::Bing)
        festival.B += "入梅 ";
    if (cur_xs >= 0 && cur_xs < 12 && w.earthlyBranch == EarthlyBranch::Wei)
        festival.B += "出梅 ";

    // 农历杂节
    if (cur_dz >= 0 && cur_dz < 81)
    { // 数九
        auto w = LunarConstants::CnNumbers[(int)floor(cur_dz / 9.0) + 1];
        if (cur_dz % 9 == 0)
            festival.B += std::format("『{}九』", w);
        else
            festival.C += std::format("九第{}天 ", (cur_dz % 9 + 1));
    }
    /*
    if (u.Ljq)
    {
        if (u.Ljq == "清明")
            festival.A += u.Ljq + ' ', festival.Fjia = 1;
        else
            festival.B += u.Ljq + ' ';
    }
*/
}
void SolarTerms::GetSexagenaryCycleDate(double jd, SexagenaryCycleDate &sc) noexcept
{
    // 以立春为界定年首
    auto lichun  = this->MiddleSolarTermArray[SolarTerm::SpringCommences];
    // 以立春为界定纪年
    double D     = lichun + (jd < lichun ? -365.0 : 0.0) + 365.25 * 16.0 - 35.0;
    // 农历纪年(10进制,1984年起算)
    double Lyear = floor(D / 365.2422 + 0.5);
    // 以下几行以正月初一定年首
    // 一般第3个月为春节;
    D            = this->CloseSuoArray[2];
    // 找春节;
    for (int j = 0; j < 14; j++)
    {
        if ((this->YearCountArray[j] = 1) || this->LeapIndex == j && j)
            continue;
        D = this->CloseSuoArray[j];
        // 无需再找下一个正月;
        if (jd < D)
        {
            D -= 365;
            break;
        }
    }
    // 计算该年春节与1984年平均春节(立春附近)相差天数估计;
    D             = D + 5810;
    // 农历纪年(10进制,1984年起算);
    double Lyear0 = floor(D / 365.2422 + 0.5);

    // 干支纪年(立春);
    // D             = Lyear + 12000;
    // double Lyear2 = obb.Gan[D%10]+obb.Zhi[D%12];

    // 干支纪年(正月);
    D             = Lyear0 + 12000;
    sc.scYear     = D;
    // 黄帝纪年;
    // double Lyear4 = Lyear0 + 1984 + 2698;

    // 纪月处理,1998年12月7(大雪)开始连续进行节气计数,0为甲子;
    int mk        = (int)floor((jd - this->MiddleSolarTermArray[SolarTerm::LastWinterSolstice]) / 30.43685);
    // 相对大雪的月数计算,mk的取值范围0-12;
    if (mk < 12 && jd >= this->MiddleSolarTermArray[2 * mk + 1 + SolarTerm::LastWinterSolstice])
        mk++;
    // 相对于1998年12月7(大雪)的月数,900000为正数基数
    D          = mk + (int)floor((this->MiddleSolarTermArray[SolarTerm::SummerSolstice] + 390.0) / 365.2422) * 12.0 + 900000;
    sc.scMonth = D;

    // 纪日,2000年1月7日起算;
    D          = jd - 6 + 9000000;
    sc.scDay   = D;
}

/*
double SolarTerms::Calc(double jd, bool qi) noexcept
{
    jd += Constants::J2000;

    auto DataSize    = suoKB.size();
    auto currentData = suoKB.data();

    int pc           = 14;
    if (qi)
    {
        DataSize    = qiKB.size();
        currentData = qiKB.data();
        pc          = 7;
    }

    auto firstJd = currentData[0].jd - pc;
    auto lastJd  = currentData[DataSize - 1].jd - pc;
    // 1960.1.1;
    auto Jd1960  = 2436935.0;

    // 平气朔表中首个之前，使用现代天文算法。
    // 1960.1.1以后，使用现代天文算法 (这一部分调用了qi_high和so_high,所以需星历表支持);
    if (jd < firstJd || jd >= Jd1960)
    {
        if (qi)
        {
            // 2451259是1999.3.21,太阳视黄经为0,春分.定气计算;
            return floor(this->CalcSolarTermPolicyHigh(floor((jd + pc - 2451259.0) / 365.2422 * 24.0) * Constants::PI / 12.0) + 0.5);
        }
        else
        {
            // 2451551是2000.1.7的那个朔日,黄经差为0.定朔计算;
            return floor(this->CalcMonthPolicyHigh(floor((jd + pc - 2451551.0) / 29.5306) * Constants::PI * 2.0) + 0.5);
        }
    }
    double D = 0.0;
    // 平气或平朔;
    if (jd >= firstJd && jd < lastJd)
    {
        for (int i = 0; i < DataSize; i++)
        {
            if ((jd + pc) < currentData[i + 1].jd)
                break;

            D = currentData[i].jd + currentData[i].coefficient * floor((jd + pc - currentData[i].jd) / currentData[i].coefficient);
            D = floor(D + 0.5);

            // 如果使用太初历计算-103年1月24日的朔日,结果得到的是23日,这里修正为24日(实历)。修正后仍不影响-103的无中置闰;
            // 如果使用秦汉历，得到的是24日，本行D不会被执行。;
            if (D == 1683460.0)
                D++;
            return D - Constants::J2000;
        }
    }

    // 定气或定朔;
    if (jd >= lastJd && jd < Jd1960)
    {
        int n = 0;
        if (qi)
        {
            // 2451259是1999.3.21,太阳视黄经为0,春分.定气计算;
            D              = floor(this->CalcSolarTermPolicyLow(floor((jd + pc - 2451259.0) / 365.2422 * 24.0) * Constants::PI / 12.0) + 0.5);
            // ====找定气修正值=====;

            // 计算索引大小;
            int indexSize  = (int)floor((jd - lastJd) / 365.2422 * 24.0);

            // 计算数组索引;
            int arrayIndex = indexSize / 16;

            // 根据索引获取数据;
            auto data      = QB.at(arrayIndex);

            // 位移;
            int shift      = indexSize % 16;

            // 按位取数据;
            n              = (data >> (shift * 2)) & 3;
        }
        else
        {
            // 2451551是2000.1.7的那个朔日,黄经差为0.定朔计算
            D              = floor(this->CalcMonthPolicyLow(floor((jd + pc - 2451551.0) / 29.5306) * Constants::PI * 2.0) + 0.5);

            // ========找定朔修正值======;
            // 计算索引大小;
            int indexSize  = (int)floor((jd - lastJd) / 29.5306);

            // 计算数组索引;
            int arrayIndex = indexSize / 16;

            // 根据索引获取数据;
            auto data      = SB.at(arrayIndex);

            // 位移;
            int shift      = indexSize % 16;

            // 按位取数据;
            n              = (data >> (shift * 2)) & 3;
        }
        if (n == 1)
            return D + 1;
        if (n == 2)
            return D - 1;
        return D;
    }
    return 0.0;
}
*/